﻿/*
 * Сделано в SharpDevelop.
 * Пользователь: max
 * Дата: 10.09.2012
 * Время: 22:56
 * 
 * Для изменения этого шаблона используйте Сервис | Настройка | Кодирование | Правка стандартных заголовков.
 */
using System;
using System.Net;
using System.IO;
using System.Collections.Concurrent;
using System.Windows.Media.Imaging;

namespace jellybird.core
{
	/// <summary>
	/// Description of TwImageCache.
	/// </summary>
	public class TwImageProfileCache
	{
		private ConcurrentDictionary<long,BitmapImage> m_dict;
		private TwImageSize m_size;
		
		#region singleton logic
		
		private static object sync_lock=new object();
		private static TwImageProfileCache instance_mini;
		private static TwImageProfileCache instance_normal;
		private static TwImageProfileCache instance_bigger;
		
		public static TwImageProfileCache GetImageCacheMini()
		{
			if(instance_mini!=null)
				return instance_mini;
			
			lock(sync_lock)
			{
				if(instance_mini==null)
				{
					TwImageProfileCache temp=new TwImageProfileCache(TwImageSize.mini);
					System.Threading.Interlocked.Exchange(ref instance_mini,temp);
				}
			}
			return instance_mini;
		}
		
		public static TwImageProfileCache GetImageCacheNormal()
		{
			if(instance_normal!=null)
				return instance_normal;
			
			lock(sync_lock)
			{
				if(instance_normal==null)
				{
					TwImageProfileCache temp=new TwImageProfileCache(TwImageSize.normal);
					System.Threading.Interlocked.Exchange(ref instance_normal,temp);
				}
			}
			return instance_normal;
		}
		
		public static TwImageProfileCache GetImageCacheBigger()
		{
			if(instance_bigger!=null)
				return instance_bigger;
			
			lock(sync_lock)
			{
				if(instance_bigger==null)
				{
					TwImageProfileCache temp=new TwImageProfileCache(TwImageSize.bigger);
					System.Threading.Interlocked.Exchange(ref instance_bigger,temp);
				}
			}
			return instance_bigger;
		}
		
		private TwImageProfileCache(TwImageSize size)
		{
			m_dict=new ConcurrentDictionary<long, BitmapImage>(1,50);
			m_size=size;
		}
		#endregion
		
		public TwImageSize TwImageSize
		{
			get{return m_size;}
		}
		
		public BitmapImage GetProfileImage(TwUser user_object)
		{
			BitmapImage ret=null;
			
			ret=m_dict.GetOrAdd
				(user_object.Id,
				 (key)=>add_image_factory_2(get_profile_image_uri(TwImageSize,user_object)));
			
			return ret;
		}
		
		private BitmapImage add_image_factory_2(string url)
		{
			BitmapImage ret=new BitmapImage();
			ret.BeginInit();
			
			/*
			 * http://code.logos.com/blog/2010/07/exceptions_thrown_by_bitmapimage_and_bitmapframe.html
			 */
			ret.CreateOptions=BitmapCreateOptions.IgnoreColorProfile;
			
			ret.DecodeFailed+=(s,e)=>
			{
				#if DEBUG
				Helper.OnDebugMessage(string.Format("Decode failed {0}, {1}",(s as BitmapImage).UriSource,e.ErrorException.Message));
				#endif
			};
			
			ret.DownloadFailed+=(s,e)=>
			{
				#if DEBUG
				Helper.OnDebugMessage(string.Format("Download failed {0}, {1}",(s as BitmapImage).UriSource,e.ErrorException.Message));
				#endif
			};
			
			ret.DecodePixelHeight=Helper.TwSize2Size(TwImageSize).Height;
			ret.DecodePixelWidth=Helper.TwSize2Size(TwImageSize).Width;
			ret.UriSource=new Uri(url,UriKind.Absolute);
			ret.EndInit();
			
			
			
			ret.DownloadCompleted+=(s,e)=>
			{
				
				#if DEBUG
//				Helper.OnDebugMessage(string.Format("Complete download and freeze {0}, total in cache={1}",(s as BitmapImage).UriSource,m_dict.Count));
				#endif
				
				(s as BitmapImage).Freeze();
			};
			
			
			return ret;
		}
		
		private BitmapImage add_image_factory(string url)
		{
			#if DEBUG
			Helper.OnDebugMessage(string.Format("Begin download {0}",url));
			#endif
			
			//если биндиниг асинхронный
			//то метод по идее работает в back thread
			
			//сначала поток для ресурса...
			WebClient web_client=new WebClient();
			Stream web_stream=web_client.OpenRead(url);
			//читаем поток в Memory
			MemoryStream image_stream=new MemoryStream();
			byte[] buf=new byte[512];
			int readed=0;
			while((readed=web_stream.Read(buf,0,buf.Length))!=0)
			{
				image_stream.Write(buf,0,readed);
			}
			
			#if DEBUG
			Helper.OnDebugMessage(string.Format("Complete download {0} len={1}",url,web_client.ResponseHeaders[HttpResponseHeader.ContentLength]));
			#endif
			
			//и вот это обязательно
			image_stream.Position=0;
			//освободить клиент и стрим MS велит
			web_stream.Close();
			web_client.Dispose();
			
			//поток получен
			//создаём ImageSource
			BitmapImage ret=new BitmapImage();
			ret.BeginInit();
			ret.DecodePixelHeight=Helper.TwSize2Size(TwImageSize).Height;
			ret.StreamSource=image_stream;
			ret.EndInit();
			
//			image_stream.Close();
			
			#if DEBUG
			Helper.OnDebugMessage(string.Format("EndInit() called {0}",url));
			#endif
			
			
			
			//чтобы читалось с других потоков
			ret.Freeze();
			
			return ret;
		}

		
		
		private string get_profile_image_uri(TwImageSize size,TwUser user)
		{
			string ret=string.Empty;
			
			int ind_of_normal=user.ProfileImageUrlHttps.LastIndexOf(Constants.NORMAL,StringComparison.Ordinal);
			int normal_len=Constants.NORMAL.Length;
			if(ind_of_normal==-1)
				return user.ProfileImageUrlHttps;
			
			switch (size)
			{
				case TwImageSize.bigger:
					ret=user.ProfileImageUrlHttps.Remove(ind_of_normal,normal_len).Insert(ind_of_normal,Constants.BIGGER);
					break;
				case TwImageSize.normal:
					ret=user.ProfileImageUrlHttps;
					break;
				case TwImageSize.mini:
					ret=user.ProfileImageUrlHttps.Remove(ind_of_normal,normal_len).Insert(ind_of_normal,Constants.MINI);
					break;
				case TwImageSize.original:
					//это предположительно
					ret=user.ProfileImageUrlHttps.Remove(ind_of_normal-1,normal_len+1); //символ "_" тоже
					break;
				default:
					ret=user.ProfileImageUrlHttps;
					break;
			}
			return ret;
		}
	}
	
	
	
}
